package com.acheli;

import com.acheli.registry.config.Config;
import com.acheli.registry.config.CustomDataBus;
import com.acheli.registry.config.GsonFactoryConfig;
import com.acheli.registry.event.CustomDynamicEntityPool;
import com.acheli.registry.event.Debugging;
import com.acheli.registry.factories.ACHFactories;
import com.acheli.registry.keybind.KeyBinding;
import com.acheli.registry.network.ACHMessages;
import com.acheli.registry.block.ACHBlocks;
import com.acheli.registry.entity.ACHEntities;
import com.acheli.registry.entity.model.OBJModelRegistry;
import com.acheli.registry.entity.render.ACHEntitiesRenderBus;
import com.acheli.registry.item.ACHItems;
import com.acheli.registry.network.packet.GsonComponentFLRegistryC2SPacket;
import com.acheli.registry.network.packet.VehiclePackRloadEventC2SPacket;
import com.acheli.rideable.entites.ComponentEntity;
import com.acheli.rideable.entites.RideableEntity;
import com.acheli.rideable.functionLathes.component.DefaultComponentFactoryRegistry;
import com.acheli.rideable.functionLathes.component.compile.EventToJS;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.network.chat.Component;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackSource;
import net.minecraft.server.packs.repository.RepositorySource;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.*;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddPackFindersEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.EntityLeaveLevelEvent;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import org.slf4j.Logger;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(ACHeli.MODID)
public class ACHeli
{
    // Define mod id in a common place for everything to reference
    public static final String MODID = "archers_helicopter";
    // Directly reference a slf4j logger
    public static final Logger LOGGER = LogUtils.getLogger();
    private static int tickCount = 0;
    private static int lastSendTick = 0;
    public static HashMap<String, Class<?>> EntitiesFactoryRegisterMap = new HashMap<>();
    public static HashMap<String, Class<?>> GsonEntitiesFactoryRegisterMap = new HashMap<>();
    public static HashMap<String, GsonFactoryConfig> GsonEntitiesConfigRegisterMap = new HashMap<>();
    public static HashMap<String, Class<?>> GsonComponentFLRegisterMap = new HashMap<>();

    public static void reloadVehicles() {
            try {
                int tick = tickCount;
                boolean pass = lastSendTick==0;
                if (pass||(tick - lastSendTick) > 20) {
                    Player player = Minecraft.getInstance().player;
                    if (player != null && player.level().isClientSide) {
                        ACHMessages.sendToServer(new VehiclePackRloadEventC2SPacket());
                        CustomDataBus.componentFLRegistryC2SPacketCacheList.clear();
                        CustomDataBus.dynamicResourcePackHashMap.forEach((l, d)->{
                            Minecraft.getInstance().getTextureManager().release(l);
                        });
                        CustomDataBus.dynamicResourcePackHashMap.clear();
                        CustomDataBus.load(); //刷新
                        CustomDataBus.dynamicResourcePackHashMap.forEach((l, d)->{
                            try {
                                Minecraft.getInstance().getTextureManager().register(l, new DynamicTexture(NativeImage.read(d.getInputStream())));
                            } catch (Exception e) {
                                System.out.println("NativeImage load error! \n" + e.getMessage());
                            }
                        });
                        ACHFactories.register();
                        for (GsonComponentFLRegistryC2SPacket gsonComponentFLRegistryC2SPacket : CustomDataBus.componentFLRegistryC2SPacketCacheList) {
                            ACHMessages.sendToServer(gsonComponentFLRegistryC2SPacket);
                        }
                        List<Entity> list = CustomDynamicEntityPool.entityMap.get(RideableEntity.class);
                        for (Entity entity : list.stream().toList()) {
                            if (entity instanceof RideableEntity rideableEntity) {
                                rideableEntity.reloadData();
                            }
                        }
                        lastSendTick = tickCount;
                        player.sendSystemMessage(Component.literal("[acheli] You has reloaded the vehicle packs."));
                    }
                }
            } catch (Exception e) {
                System.err.println(e.getMessage());
                Player player = Minecraft.getInstance().player;
                if (player != null) {
                    player.sendSystemMessage(Component.literal("[acheli] Reload Failure! " + e.getMessage()));

                }
            }
    }

    public ACHeli(FMLJavaModLoadingContext context)
    {
        IEventBus modEventBus = context.getModEventBus();
        DefaultComponentFactoryRegistry.register();
        CustomDataBus.load();
        // Register the commonSetup method for modloading
        modEventBus.addListener(this::commonSetup);
        ACHFactories.register();
        // Register the Deferred Register to the mod event bus so blocks get registered
        ACHBlocks.register(modEventBus);
        // Register the Deferred Register to the mod event bus so items get registered
        ACHItems.register(modEventBus);
        OBJModelRegistry.register(modEventBus);
        // Register the Deferred Register to the mod event bus so tabs get registered
        ACHEntities.register(modEventBus);
        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);
        // Register the item to a creative tab
        modEventBus.addListener(ACHItems::addCreative);

        // Register our mod's ForgeConfigSpec so that Forge can create and load the config file for us
        context.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
    }

    private void commonSetup(final FMLCommonSetupEvent event)
    {
        // Some common setup code
        LOGGER.info("HELLO FROM COMMON SETUP");

//        if (Config.logDirtBlock)
//            LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT));
//
//        LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber);
//
//        Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString()));

        ACHMessages.register();
    }

    // Add the example block item to the building blocks tab


    @SubscribeEvent
    public void onServerStarting(ServerStartingEvent event)
    {
        // Do something when the server starts
        LOGGER.info("HELLO from server starting");
    }
    @SubscribeEvent
    public void onPreparableReload(RegisterClientReloadListenersEvent event) {
        event.registerReloadListener(new PreparableReloadListener() {
            @Override
            public CompletableFuture<Void> reload(PreparationBarrier pPreparationBarrier, ResourceManager pResourceManager, ProfilerFiller pPreparationsProfiler, ProfilerFiller pReloadProfiler, Executor pBackgroundExecutor, Executor pGameExecutor) {
                CustomDataBus.load(); //刷新
                List<Entity> list = CustomDynamicEntityPool.entityMap.get(RideableEntity.class);
                for (Entity entity : list) {
                    if (entity instanceof RideableEntity rideableEntity) {
                        rideableEntity.reloadData();
                    }
                }
                return null;
            }
        });
    }

//    @SubscribeEvent
//    public void onResourceReload(FMLClientSetupEvent event) {
//        // 获取外部资源目录（示例路径，需根据实际位置调整）
//        File externalDir = new File("external_resources");
//
//        // 添加资源目录到 Minecraft 的加载路径
//        if (externalDir.exists()) {
//            Minecraft.getInstance().getResourceManager().
//            );
//        }
//    }

    // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent
    @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
    public static class ClientModEvents
    {
        @SubscribeEvent
        public static void onClientSetup(FMLClientSetupEvent event)
       {
            ACHEntitiesRenderBus.init(event);
            // Some client setup code
            LOGGER.info("HELLO FROM CLIENT SETUP");
            LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName());
        }

        @SubscribeEvent
        public static void addPackFinders(AddPackFindersEvent event) {
            System.out.println("AddPackFindersEvent");
            if (event.getPackType() == PackType.CLIENT_RESOURCES) {
                CustomDataBus.dynamicResourcePackHashMap.forEach((PACKNAME, dynamicRes) -> {
                    //                String PACKNAME = "testpack";
//                String packRoot = "geo";
//                String packMcPath = "geo/gec.geo.json";
                    LOGGER.info("addPackFinder => " + PACKNAME);
                    String HEAD = "acheli_";
                    RepositorySource source = (packConsumer) -> {
                        // 1. 创建 ResourcesSupplier
                        Pack.ResourcesSupplier supplier = (packId) -> dynamicRes;

                        // 2. 手动创建 Pack.Info（避免依赖 pack.mcmeta）
                        Pack.Info packInfo = new Pack.Info(
                                Component.literal(HEAD+PACKNAME), // description
                                15, // dataFormat（对应数据版本，原版1.20.1为15）
                                15, // resourceFormat（资源版本，原版1.20.1为15）
                                FeatureFlagSet.of(), // requestedFeatures（空表示无特性要求）
                                false // hidden（是否隐藏）
                        );

                        // 3. 创建 Pack 实例
                        Pack pack = Pack.create(
                                String.valueOf(PACKNAME), // 唯一ID
                                Component.literal(HEAD+PACKNAME), // 显示名称
                                true, // 强制启用
                                supplier, // 资源供应商
                                packInfo, // 手动构造的元数据
                                PackType.CLIENT_RESOURCES, // 资源类型
                                Pack.Position.TOP, // 显示位置
                                true, // 固定位置
                                PackSource.BUILT_IN // 来源标识
                        );

                        packConsumer.accept(pack);
                    };
                    event.addRepositorySource(source);
                });

            }
        }

        @SubscribeEvent
        public static void onKeyRegister(RegisterKeyMappingsEvent event) {
            KeyBinding.register(event);
        }
        @SubscribeEvent
        public static void onTextureStitchEvent(TextureStitchEvent event) { //F3 + T 触发
            reloadVehicles();
        }

    }

    @Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE)
    public static class ClientForgeHandler {
        @SubscribeEvent
        public static void onClientTick(TickEvent.ClientTickEvent event) {
            // 处理事件逻辑
            if (event.phase == TickEvent.Phase.START) { // 可选：判断阶段
                // 在 Tick 开始时执行
                tickCount++;
            } else if (event.phase == TickEvent.Phase.END) {
                // 在 Tick 结束时执行

            }
        }
    }

    @Mod.EventBusSubscriber(modid = MODID, value = Dist.CLIENT)
    public static class ClientOnKeyEvents {
        @SubscribeEvent
        public static void onClientTick(TickEvent.ClientTickEvent event) {
            Debugging.run();
            Player player = Minecraft.getInstance().player;
            if (player != null && player.getVehicle() instanceof ComponentEntity componentEntity) {
                componentEntity.doFactory((factoryNotNull)->{
                    factoryNotNull.getProductFunction().onClientTick();
                    factoryNotNull.getProductFunction().getFL().onClientTick();
                });
                if (componentEntity.getVehicle() instanceof RideableEntity rideable) {
                    rideable.doFactory((factoryNotNull)->{
                        factoryNotNull.getProductFunction().onClientTick();
                        factoryNotNull.getProductFunction().getFL().onClientTick();
                    });
                }
            }
        }

        @SubscribeEvent
        public static void onKeyInput(InputEvent.Key event) {
            InputConstants.Key inputKey = InputConstants.getKey(event.getKey(), event.getScanCode());
            Player player = Minecraft.getInstance().player;
            if (player != null && player.getVehicle() instanceof ComponentEntity componentEntity) {
                componentEntity.doFactory((factoryNotNull)->{
                    factoryNotNull.getProductFunction().getFL().inputEventHolder.put(inputKey.getName(), event.getAction());
                    factoryNotNull.getProductFunction().runScript(new EventToJS("onKey"));
                });
                if (componentEntity.getVehicle() instanceof RideableEntity rideable) {
                    rideable.doFactory((factoryNotNull)->{
                        factoryNotNull.getProductFunction().getFL().inputEventHolder.put(inputKey.getName(), event.getAction());
                        factoryNotNull.getProductFunction().runScript(new EventToJS("onKey"));
                    });
                }
            }
        }
        @SubscribeEvent
        public static void onEntitySpawn(EntityJoinLevelEvent event) {
            if (event.getLevel().isClientSide()) {
                CustomDynamicEntityPool.joinEvent(event);
            }
        }

        @SubscribeEvent
        public static void onEntityLeave(EntityLeaveLevelEvent event) {
            if (event.getLevel().isClientSide()) {
                CustomDynamicEntityPool.leaveEvent(event);
            }
        }

    }

}
